package com.lu.integrate.message.center.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * @program Equity3
 * @description: 线程池配置
 * @author: zhanglu
 * @create: 2022-10-12 14:27:00
 */
@Configuration
public class ThreadPoolConfig {

    /**
     * 系统公用执行线程执行器
     *  - 每个模块需要用到线程池异步处理时，都可以使用，也可以在方法头上加 {@link Async}，但是某些场景这种方式会失效，所以可以手动触发
     *  - 并行度：默认cup核心数
     *  - 队列容量：1000
     *  - 拒绝策略：当任务量太大，超过了线程数、队列容量大小，则会交给调用方线程处理后续任务
     *
     * 注意：
     *  - 公用的执行器，在实际过程中，各个模块间会产生一定的影响
     *    例子：
     *     - A功能、B功能代码逻辑 都是循环1000次 丢给线程池处理
     *     - 假如A、B同时触发了，实际上并不是所有的线程都在执行A功能，优先处理先入队的
     * @return
     */

    /**
     * 消息队列消费者执行器
     * @return
     */
    @Bean
    public ThreadPoolTaskExecutor messageQueueConsumerExecutor() {
        //根据ThreadPoolTaskExecutor 创建建线程池
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        /***************深思熟虑，看经验，考虑会不会响应其他业务功能***************/
        //设置初始的线程数量
        executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());
        //设置最大的线程数量
        executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 2);
        //任务队列设置最大 任务数量
        executor.setQueueCapacity(1000);
        //设置 超出初始化线程的 存在时间为60秒
        executor.setKeepAliveSeconds(120);
        //设置 线程前缀
        executor.setThreadNamePrefix("message-queue-consumer-executor-");
        //线程池的饱和策略 我这里设置的是 CallerRunsPolicy 也就是由用调用者所在的线程来执行任务 共有四种
        //AbortPolicy：直接抛出异常，这是默认策略；
        //CallerRunsPolicy：用调用者所在的线程来执行任务；
        //DiscardOldestPolicy：丢弃阻塞队列中靠最前的任务，并执行当前任务；
        //DiscardPolicy：直接丢弃任务；
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //设置在关闭线程池时是否等待任务完成
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //设置等待终止的秒数
        executor.setAwaitTerminationSeconds(60);
        return executor;
    }

}
